﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Xfm
{
    public static class EfExtentions
    {
        /// <summary>
        /// string排序，忽略大小写，自动判断Order属性类型
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="prop"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public static IOrderedQueryable<TSource> OrderString<TSource>(this IQueryable<TSource> source, string prop, bool isAsc)
        {
            if (string.IsNullOrEmpty(prop))
                throw new ArgumentNullException(nameof(prop));

           

            Type orderKeyType = null;
            foreach (var item in typeof(TSource).GetProperties())
            {
                if (string.Equals(item.Name, prop, StringComparison.OrdinalIgnoreCase))
                {
                    orderKeyType = item.PropertyType;
                    prop = item.Name;
                }
            }
            if (orderKeyType == null)
            {
                throw new Exception("排序字段不正确,prop:" + prop);
            }
            //TODO Ef扩展 待测试
            if (isAsc)
                return source.OrderBy(u => EF.Property<object>(u, prop));
            else
                return source.OrderByDescending(u => EF.Property<object>(u, prop));


            //var method = typeof(EfExtentions).GetMethod("AscOrDesc");
            //method = method.MakeGenericMethod(typeof(TSource), orderKeyType);
            //return (IOrderedQueryable<TSource>)method.Invoke(null, new object[] { source, prop, isAsc });
        }
        /// <summary>
        /// string排序，忽略大小写，需要指定Order属性类型
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="prop"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public static IOrderedQueryable<TSource> AscOrDesc<TSource, TKey>(this IQueryable<TSource> source, string prop, bool isAsc)
        {
            Expression<Func<TSource, TKey>> expression = CreateLamdba<TSource, TKey>(prop);
            if (isAsc)
                return source.OrderBy(expression);
            else
                return source.OrderByDescending(expression);
        }
        /// <summary>
        /// 生成Lamdba表达式
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="prop"></param>
        /// <returns></returns>
        public static Expression<Func<TSource, TKey>> CreateLamdba<TSource, TKey>(string prop)
        {
            var param = Expression.Parameter(typeof(TSource), "m");
            var body = Expression.Property(param, prop);
            Expression<Func<TSource, TKey>> lamdba = Expression.Lambda<Func<TSource, TKey>>(body, param);
            return lamdba;
        }

    }
}
